import cv2
import numpy as np
import copy

def on_segment(p, q, r):
    if (q[0] <= max(p[0], r[0]) and q[0] >= min(p[0], r[0]) and q[1] <= max(p[1], r[1]) and q[1] >= min(p[1], r[1])):
        return True
    return False

def orientation(p, q, r):
    val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])
    if val == 0:
        return 0  # 共线
    elif val > 0:
        return 1  # 顺时针
    else:
        return 2  # 逆时针

def do_intersect(p1, q1, p2, q2):
    o1 = orientation(p1, q1, p2)
    o2 = orientation(p1, q1, q2)
    o3 = orientation(p2, q2, p1)
    o4 = orientation(p2, q2, q1)

    # 一般情况
    if o1 != o2 and o3 != o4:
        return True

        # 处理共线情况
    if o1 == 0 and on_segment(p1, q1, p2): return True
    if o2 == 0 and on_segment(p1, q1, q2): return True
    if o3 == 0 and on_segment(p2, q2, p1): return True
    if o4 == 0 and on_segment(p2, q2, q1): return True

    # 不相交
    return False

def eq(list1, list2):
    for i in range(len(list1)):
        if abs(list1[i] - list2[i]) > 3:
            print("false:", list1, "   --list2:", list2)
            return False
    return True

def get_lines(image):
    #image = cv2.imread(filename)
    if image is None:
        return None, []
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=20, maxLineGap=10)
    return image, lines

def get_edge_pos(line_list, image):#获取表格的边界
    max_x = -1
    min_x = -1
    max_y = -1
    min_y = -1
    for l in line_list:
        if l[0] >= max_x:
            max_x = l[0]

        if l[2] >= max_x:
            max_x = l[2]

        if min_x >= l[0] or min_x == -1:
            min_x = l[0]

        if min_x >= l[2] or min_x == -1:
            min_x = l[2]

        if l[1] >= max_y:
            max_y = l[1]

        if l[3] >= max_y:
            max_y = l[3]

        if min_y >= l[1] or min_y == -1:
            min_y = l[1]

        if min_y >= l[3] or min_y == -1:
            min_y = l[3]

    min_x = max(0, min_x)
    min_y = max(0, min_y)
    max_x = min(max_x, image.shape[1])
    max_y = min(max_y, image.shape[0])

    return min_x, min_y, max_x, max_y

def scale_line(line, max_x, max_y):

    if abs(line[1] - line[3]) <= 3:
        if line[0] - line[2] < 0:
            line[0] = max(line[0]-5, 0)
            line[2] = min(line[2] + 5, max_x)
        else:
            line[2] = max(line[2]-5, 0)
            line[0] = min(line[0] + 5, max_x)
    if abs(line[0] - line[2]) <= 3:
        if line[1] - line[3] < 0:
            line[1] = max(line[1]-5, 0)
            line[3] = min(line[3] + 5, max_y)
        else:
            line[3] = max(line[3]-5, 0)
            line[1] = min(line[1] + 5, max_y)

    return line

def parse_pic(filename, count):

    edge_size = 5
    image, lines = get_lines(filename) #获取所有直线
    if image is None:
        print("read file failed:", filename)
        return None, None

    if lines is None:
        print("no line")
        return None, image

    line_list = []   #存储所有相交的直线
    max_line_w = -1  #所有相交线段中的最大宽度
    max_line_h = -1  #所有相交线段中的最大高度

    # 检查所有线段对是否相交
    for i in range(len(lines)):

        line1 = lines[i][0]
        p1 = (line1[0], line1[1])
        p2 = (line1[2], line1[3])

        for j in range(i+1, len(lines)-1):
            line2 = lines[j][0]
            p3 = (line2[0], line2[1])
            p4 = (line2[2], line2[3])

            if do_intersect(p1, p2, p3, p4) is True: #是否相交
                max_line_h = max(abs(line1[3] - line1[1]), max_line_h)
                max_line_w = max(abs(line1[2] - line1[0]), max_line_w)
                line_list.append(line1)
                line_list.append(line2)
                #cv2.line(image, p1, p2, (0, 0, 0), 2)
                #cv2.line(image, p3, p4, (0, 0, 0), 2)

    #cv2.imshow('table', image)
    #cv2.waitKey(0)

    if len(line_list) == 0:
        print('no talble in ', filename)
        return None, image
    min_x, min_y, max_x, max_y = get_edge_pos(line_list, image) #获取所有相交直线的最大轮廓

    table_start_y = -1   #表格的最小Y
    table_end_y = max_y # 最大Y
    table_start_x = -1  # 最小x
    table_end_x = 0     #最大x

    for item in line_list:
        if abs(item[1] - table_end_y) < edge_size or abs(item[3] - table_end_y) < edge_size: # 找到所有Y值是table_end_y的线段（误差为edge_size）
            if item[1] < table_start_y or item[3] < table_start_y or table_start_y == -1:
                table_start_y = min(item[1], item[3])
            if item[0] < table_start_x or item[2] < table_start_x or table_start_x == -1:
                table_start_x = min(item[0], item[2])
            if item[0] > table_end_x or item[2] > table_end_x:
                table_end_x = max(item[0], item[2])

    print("start y:", table_start_y, "end y:", table_end_y)
    print("start x:", table_start_x, "end x:", table_end_x)

    cropped_image = copy.deepcopy(image[max(table_start_y-edge_size, 0):min(table_end_y+edge_size, image.shape[0]),
                    max(table_start_x-edge_size, 0):min(table_end_x+edge_size, image.shape[1])])

    image[max(table_start_y-edge_size, 0):min(table_end_y+edge_size, image.shape[0]),
        max(table_start_x-edge_size, 0):min(table_end_x+edge_size, image.shape[1])] = 255

    return cropped_image, image

def split_pic(filedata):

    src_file = cv2.imread(filedata)
    if src_file is None:
        print("read file failed")
        return None

    files = {}
    count = 0

    while True:

        table_file, another_file = parse_pic(src_file, count)
        if table_file is None:
            if another_file is not None:
                files['text'+str(count)] = another_file
            break

        files['table'+str(count)] = table_file
        count += 1
        src_file = another_file
    return files

if __name__ == '__main__':

    filename = 'pic4.png'
    files = split_pic(filename)
    if files is None:
        print("splite_pic failed")
    else:
        for k in files:
            image = cv2.imwrite(k+'.png', files[k])
